home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / SESSMGR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-30  |  27.1 KB  |  1,205 lines

  1. #ifdef UNIX
  2. /*
  3.  * Session manager and session manager switch
  4.  *
  5.  * The session manager switch intercepts all session and console I/O calls and
  6.  * forwards them to session managers based on the switch entry managing the
  7.  * session, or the system default session manager for new sessions.  New
  8.  * sessions may also be started attached to specific session managers.
  9.  * Sessions can also be "reparented" from one session manager to another.
  10.  *
  11.  * Per-session options are now supported.  Per-session-*manager* options have
  12.  * assigned slots in the session manager definition, but are not yet supported.
  13.  */
  14.  
  15. #include "global.h"
  16. #include "commands.h"
  17. #include <signal.h>
  18. #include "hardware.h"
  19. #include "proc.h"
  20. #include "socket.h"
  21. #undef tputs
  22. #include "tty.h"
  23. #include "sessmgr.h"
  24.  
  25. #if !defined(_lint)
  26. static char rcsid[] OPTIONAL = "$Id: sessmgr.c,v 1.20 1997/07/31 00:44:20 root Exp root $";
  27. #endif
  28.  
  29. static int dosmstatus (int, char **, void *);
  30. static int dosmdefault (int, char **, void *);
  31. static int dosmcreate (int, char **, void *);
  32. static int dosmreparent (int, char **, void *);
  33. static int dosmoptions (int, char **, void *);
  34.  
  35. void sm_status (int pos, char *str);
  36. extern void displayStatLine (int offset, int phase, int onlymarquee);
  37. extern int Numrows;
  38. extern int BLOCKStatline, INStatline;
  39.  
  40.  
  41. /*
  42.  * The session manager switch:  an array of pointers to session managers.
  43.  */
  44.  
  45. #ifdef SM_CURSES
  46. extern struct sessmgr_sw curses_sessmgr;
  47. #endif
  48. #ifdef SM_RAW
  49. extern struct sessmgr_sw raw_sessmgr;
  50. #endif
  51. #ifdef SM_DUMB
  52. extern struct sessmgr_sw dumb_sessmgr;
  53. #endif
  54.  
  55. static struct sessmgr_sw *sessmgr_sw[] =
  56. {
  57. #ifdef SM_CURSES
  58.     &curses_sessmgr,
  59. #endif
  60. #ifdef SM_DUMB
  61.     &dumb_sessmgr,
  62. #endif
  63. #ifdef SM_RAW
  64.     &raw_sessmgr,
  65. #endif
  66.     0,
  67. };
  68.  
  69.  
  70.  
  71. static int sesm_initted;
  72.  
  73. /*
  74.  * Commands for session manager administration
  75.  */
  76.  
  77. static struct cmds SMcmds[] =
  78. {
  79.     { "create",    dosmcreate,            0, 0, NULLCHAR },
  80.     { "default",    dosmdefault,            0, 0, NULLCHAR },
  81.     { "options",    dosmoptions,            0, 0, NULLCHAR },
  82.     { "reparent",    dosmreparent,            0, 0, NULLCHAR },
  83.     { "status",    dosmstatus,            0, 0, NULLCHAR },
  84.     { NULLCHAR,    NULLFP ((int, char **, void *)),0, 0, NULLCHAR }
  85. };
  86.  
  87.  
  88. static struct cmds SMsessions[] =
  89. {
  90. #ifdef MAILBOX
  91.     { "bbs",    dobbs,          1024, 0, NULLCHAR },
  92. #endif
  93. #ifdef AX25
  94. #ifdef ALLSESSIONS
  95.     { "connect",    doconnect,   1024, 3, "connect <interface> <callsign>" },
  96. #endif
  97. #endif
  98. #ifdef ALLCMD
  99.     { "dir",    dodir,         0, 0, NULLCHAR },
  100. #endif
  101. #ifdef DIALER
  102.     { "dialer",    dodialer,     512, 2, "dialer <iface> [<file> [<seconds> [<pings> [<hostid>]]]]" },
  103. #endif
  104. #ifdef ALLCMD
  105.     { "finger",    dofinger,    1024, 2, "finger name[@host]" },
  106. #endif
  107. #ifdef ALLSESSIONS
  108.     { "ftp",    doftp,          2048, 2, "ftp <address>" },
  109. #endif
  110. #ifdef ALLCMD
  111.     { "more",    domore,        0, 2, "more <file> [searchstring]" },
  112. #endif
  113.     { "ping",    doping,       512, 4, "ping <hostid> <length> <interval> [incflag]" },
  114. #ifdef RLOGINCLI
  115.     { "rlogin",    dorlogin,    2048, 2, "rlogin <address>" },
  116. #endif
  117. #if defined(AX25) && defined(ALLSESSIONS) && defined(ALLSERV)
  118.     { "split",    doconnect,   1024, 3, "split <interface> <callsign>" },
  119. #endif
  120. #ifdef ALLSESSIONS
  121.     { "telnet",    dotelnet,    1024, 2, "telnet <address> [port]" },
  122. #endif
  123. #ifdef ALLSERV
  124.     { "ttylink",    dotelnet,    1024, 2, "ttylink <address> [port]" },
  125. #endif
  126.     { NULLCHAR,    NULLFP ((int, char **, void *)),
  127.                     0, 0, NULLCHAR },
  128. };
  129.  
  130. #if 0
  131. extern int STATLINE;
  132. #endif
  133.  
  134.  
  135.  
  136. /*
  137.  * Used by the newscreen() entry point, the creation of the trace session
  138.  * in main(), and by reparenting.
  139.  */
  140.  
  141. static void
  142. sm_newscreen (const char *sc, struct session *sp)
  143. {
  144. struct sessmgr_sw *sm;
  145. const char *cp;
  146.  
  147.     if ((sm = sm_lookup (sc, &cp)) == (struct sessmgr_sw *) 0) {
  148.         sm = sessmgr_sw[0];    /* system-wide default session manager */
  149.         cp = 0;
  150.     }
  151.     if (!sp)
  152.         return;
  153.     sp->screen = mallocw (sizeof *sp->screen);
  154.     if (!(sm->flags & SM_INIT)) {
  155.         if (Current && Current != sp && Current->screen &&
  156.             !(Current->screen->sessmgr->flags & SM_SUSPEND)) {
  157.             (*Current->screen->sessmgr->suspend) (Current->screen->sessmgr);
  158.             Current->screen->sessmgr->flags |= SM_SUSPEND;
  159.         }
  160.         (void) (*sm->init) (sm);
  161.         sm->flags |= SM_INIT;
  162.     }
  163.     sm->refcnt++;
  164.     sp->screen->sessmgr = sm;
  165.     sp->screen->sesmdat =
  166.         (*sm->create) (sm, sp);
  167.     if (sm->sessopt && cp)
  168.         (void) (*sm->sessopt) (sm, sp->screen->sesmdat, cp);
  169.     sp->screen->flags = 0;
  170. #if 0
  171.     sp->screen->statline = STATLINE;
  172. #else
  173.     sp->screen->statline = 0;
  174. #endif
  175.     if (sp->split)
  176.         sp->screen->flags |= SMS_SPLIT;
  177.     if (!(sm->flags & SM_SPLIT))
  178.         sp->split = 0;    /* if sm can't do split, split sessions are deranged */
  179.     sp->screen->next_sm = strdup (sc);
  180.     sp->screen->use_sm = sp->screen->next_sm;
  181.     if (sm->flags & SM_SUSPEND) {
  182.         (*Current->screen->sessmgr->resume) (Current->screen->sessmgr);
  183.         Current->screen->sessmgr->flags &= ~SM_SUSPEND;
  184.     }
  185. #if 0
  186.     /* this is ugly... */
  187.     /* (it's also wrong; figure it out later...) */
  188.     if (sp->type == TRACESESSION)
  189.         sp->screen->flags |= SMS_DISCARD;
  190. #endif
  191. }
  192.  
  193.  
  194.  
  195. int
  196. dosessmgr (int argc, char **argv, void *p)
  197. {
  198.     if (argc < 2)
  199.         return dosmstatus (argc, argv, p);
  200.     return subcmd (SMcmds, argc, argv, p);
  201. }
  202.  
  203.  
  204.  
  205. int
  206. dosmstatus (int argc OPTIONAL, char **argv OPTIONAL, void *p OPTIONAL)
  207. {
  208. struct screen *sp;
  209. char *cp;
  210. int s;
  211.  
  212.     tprintf ("Known session managers are:\n");
  213.     for (s = 0; sessmgr_sw[s]; s++)
  214.         tprintf ("%s\n", sessmgr_sw[s]->name);
  215.     tprintf ("\n");
  216.     (void) dosmdefault (0, 0, 0);
  217.     tprintf ("\n#  Type         Name         Process      Manager  Options\n");
  218.     tprintf ("== ============ ============ ============ ======== ==========\n");
  219.     for (s = 0; (unsigned) s < Nsessions; s++) {
  220.         if (Sessions[s].type == FREE)
  221.             continue;
  222.         tprintf ("%-2d %-12s ", s, Sestypes[Sessions[s].type]);
  223.         if (Sessions[s].name)
  224.             tprintf ("%-12.12s ", Sessions[s].name);
  225.         else
  226.             tprintf ("             ");
  227.         if (Sessions[s].proc->name && *Sessions[s].proc->name)
  228.             tprintf ("%-12.12s", Sessions[s].proc->name);
  229.         else
  230.             tprintf ("%8.8lx    ", (uint32) Sessions[s].proc);
  231.         tprintf (" %-8.8s", Sessions[s].screen->sessmgr->name);
  232.         /* we don't support session MANAGER options just yet... */
  233.         if ((sp = Sessions[s].screen)->sessmgr->sessopt &&
  234.             (cp = (*sp->sessmgr->sessopt) (sp->sessmgr, sp->sesmdat, (char *) 0)) != NULLCHAR)
  235.             tprintf (" %s", cp);
  236.         tprintf ("\n");
  237.     }
  238.     return 0;
  239. }
  240.  
  241.  
  242.  
  243. int
  244. dosmdefault (int argc, char **argv, void *p OPTIONAL)
  245. {
  246. char const *cp;
  247.  
  248.     if (argc < 2) {
  249.         if (Current && Current->screen && Current->type == COMMAND)
  250.             cp = Current->screen->next_sm;
  251.         else if (Command && Command->screen)
  252.             cp = Command->screen->next_sm;
  253.         else
  254.             cp = "";
  255.         if (!cp || !*cp)
  256.             cp = sessmgr_sw[0]->name;
  257.         tprintf ("Session manager for new sessions is \"%s\".\n", cp);
  258.         return 0;
  259.     }
  260.     if (argc > 2) {
  261.         tprintf ("usage: sessmgr default [session-manager]\n");
  262.         return 1;
  263.     }
  264.     if (!sm_lookup (argv[1], 0)) {
  265.         tprintf ("No such session manager: \"%s\"\n", argv[1]);
  266.         return 1;
  267.     }
  268.     if (Current->screen->next_sm)
  269.         free (Current->screen->next_sm);
  270.     Current->screen->next_sm = strdup (argv[1]);
  271.     return 0;
  272. }
  273.  
  274.  
  275.  
  276. int
  277. dosmcreate (int argc, char **argv, void *p)
  278. {
  279. int rc;
  280.  
  281.     if (argc < 3) {
  282.         tprintf ("usage: sessmgr create session-manager command [args...]\n");
  283.         return 1;
  284.     }
  285.     if (!sm_lookup (argv[1], 0)) {
  286.         tprintf ("Unknown session manager \"%s\"\n", argv[1]);
  287.         return 1;
  288.     }
  289.     if (Current->type != COMMAND)
  290.         write (2, "WHOA! I'm not being run from a COMMAND session!\n", 48);
  291.     Current->screen->use_sm = argv[1];
  292.     rc = subcmd (SMsessions, argc - 1, argv + 1, p);
  293.     return rc;
  294. }
  295.  
  296.  
  297.  
  298. int
  299. dosmoptions (int argc, char **argv, void *p OPTIONAL)
  300. {
  301. struct screen *sp;
  302. char *cp;
  303. int i;
  304.  
  305.     if (argc < 2) {
  306.         tprintf ("usage: sessmgr options session [options]\n");
  307.         return 1;
  308.     }
  309.     if ((i = atoi (argv[1])) < 0 || (unsigned) i > Nsessions || Sessions[i].type == FREE) {
  310.         tprintf ("Invalid session %s\n", argv[1]);
  311.         return 1;
  312.     }
  313.     sp = Sessions[i].screen;
  314.     if (argc < 3) {
  315.         tprintf ("Options for session: ");
  316.         if (!sp->sessmgr->sessopt)
  317.             cp = 0;
  318.         else
  319.             cp = (*sp->sessmgr->sessopt) (sp->sessmgr, sp->sesmdat, (char *) 0);
  320.         if (!cp)
  321.             tprintf ("(none)\n");
  322.         else
  323.             tprintf ("%s\n", cp);
  324.         return 0;
  325.     }
  326.     if (sp->sessmgr->sessopt)
  327.         (void) (*sp->sessmgr->sessopt) (sp->sessmgr, sp->sesmdat, argv[2]);
  328.     return 0;
  329. }
  330.  
  331.  
  332.  
  333. /*
  334.  * Administration of the session manager interface
  335.  */
  336.  
  337. struct sessmgr_sw *
  338. sm_lookup (const char *smname, const char **optp)
  339. {
  340. static char buf[1024];
  341. char const *cp;
  342. int i;
  343.  
  344.     if (!smname) {
  345.         /* inherit a reasonable session manager */
  346.         if (Current && Current->screen && Current->type == COMMAND) {
  347.             smname = Current->screen->use_sm;
  348.             Current->screen->use_sm = Current->screen->next_sm;
  349.         } else if (Command && Command->screen)
  350.             smname = Command->screen->next_sm;
  351.         else
  352.             smname = "";
  353.     }
  354.  
  355.     for (i = 0, cp = smname; i < 1024 && *cp && *cp != ':'; cp++)
  356.         buf[i++] = *cp;
  357.  
  358.     /*lint -save -e661 */
  359.     if (i < 1024)
  360.         buf[i] = '\0';
  361.     /*lint -restore */
  362.     if (*cp)
  363.         cp++;
  364.     else
  365.         cp = 0;
  366.  
  367.     if (!i) {
  368.         if (optp)    /* is this wise?  sessmgr ":opt", that is */
  369.             *optp = cp;
  370.         return sessmgr_sw[0];
  371.     }
  372.     for (i = 0; sessmgr_sw[i]; i++) {
  373.         if (strcasecmp (sessmgr_sw[i]->name, buf) == 0) {
  374.             if (optp)
  375.                 *optp = cp;
  376.             return sessmgr_sw[i];
  377.         }
  378.     }
  379.     if (optp)
  380.         *optp = 0;
  381.     return 0;
  382. }
  383.  
  384.  
  385.  
  386. int
  387. sm_blocked (struct session *sp)
  388. {
  389.     /* Return TRUE if the session is blocked. */
  390.     return !(sp->screen->flags & SMS_ACTIVE) ||
  391.     (sp->screen->sessmgr->flags & SM_SUSPEND);
  392. }
  393.  
  394.  
  395.  
  396. /*
  397.  * Session reparenting.  This is mildly interesting.
  398.  *
  399.  * The idea is that a session can be destroyed and recreated.  (Actually, the
  400.  * session is retained; the screen is destroyed.)  The only fly in the oint-
  401.  * ment is that you can't retain the contents of the screen:  some session
  402.  * managers have no backing store ("dumb", and especially "none").
  403.  *
  404.  * Sessions can be reparented individually or by session manager.  Individual
  405.  * sessions can be named if they have names.
  406.  */
  407.  
  408. static void
  409. sm_reparent (struct session *sp, char *new)
  410. {
  411. struct sessmgr_sw *old, *np;
  412. int susp;
  413.  
  414.     if ((np = sm_lookup (new, 0)) == (struct sessmgr_sw *) 0)
  415.         return;
  416.     if ((old = sp->screen->sessmgr) == np)
  417.         return;
  418.     if (sp->screen->flags & SMS_SPLIT)    /* sp->split is 0 if s.m. won't split */
  419.         sp->split = 1;    /* newscreen will deactivate if needed */
  420.     susp = (old->flags & SM_STDIO) && (np->flags & SM_STDIO);
  421.     freescreen (sp);
  422.     if (susp && !(old->flags & SM_SUSPEND)) {
  423.         (*old->suspend) (old);
  424.         old->flags |= SM_SUSPEND;
  425.     }
  426.     sm_newscreen (new, sp);
  427. }
  428.  
  429.  
  430.  
  431. int
  432. dosmreparent (int argc, char **argv, void *p OPTIONAL)
  433. {
  434. struct sessmgr_sw *old;
  435. struct session *s;
  436. int i, susp;
  437.  
  438.     if (argc != 3) {
  439.         tprintf ("usage: sessmgr reparent <session> <session-manager>\n");
  440.         return 1;
  441.     }
  442.     if (!sm_lookup (argv[2], 0)) {
  443.         tprintf ("Unknown session manager \"%s\"\n", argv[2]);
  444.         return -1;
  445.     }
  446.     if (isdigit (argv[1][0])) {
  447.         if ((unsigned) (i = atoi (argv[1])) >= Nsessions || Sessions[i].type == FREE) {
  448.             tprintf ("Invalid session number %d.\n", i);
  449.             return 1;
  450.         }
  451.         sm_reparent (Sessions + i, argv[2]);
  452.         if (Sessions + i == Current)
  453.             Sessions[i].screen->flags |= SMS_ACTIVE;
  454.         else {
  455.             /* we must do this because newscreen() partially switches us */
  456.             swapscreen (Current, Sessions + i);
  457.             swapscreen (Sessions + i, Current);
  458.         }
  459.         return 0;
  460.     }
  461.     susp = -1;
  462.     for (i = 0; (unsigned) i < Nsessions; i++) {
  463.         if (Sessions[i].type == FREE)
  464.             continue;
  465.         if (Sessions[i].name && *Sessions[i].name &&
  466.             strcasecmp (Sessions[i].name, argv[1]) == 0) {
  467.             if (susp != -1)
  468.                 break;
  469.             susp = i;
  470.         }
  471.         if (Sessions[i].proc->name && *Sessions[i].proc->name &&
  472.             strcasecmp (Sessions[i].proc->name, argv[1]) == 0) {
  473.             if (susp != -1)
  474.                 break;
  475.             susp = i;
  476.         }
  477.         if (strcasecmp (Sestypes[Sessions[i].type], argv[1]) == 0) {
  478.             if (susp != -1)
  479.                 break;
  480.             susp = i;
  481.         }
  482.     }
  483.     if ((unsigned) i != Nsessions) {
  484.         tprintf ("Session ID \"%s\" is not unique\n", argv[1]);
  485.         return 1;
  486.     }
  487.     if (susp != -1) {
  488.         sm_reparent (Sessions + susp, argv[2]);
  489.         if (Sessions + susp == Current)
  490.             Sessions[susp].screen->flags |= SMS_ACTIVE;
  491.         else {
  492.             /* we must do this because newscreen() partially switches us */
  493.             swapscreen (Current, Sessions + susp);
  494.             swapscreen (Sessions + susp, Current);
  495.         }
  496.         return 0;
  497.     }
  498.     for (i = 0; sessmgr_sw[i]; i++) {
  499.         if (sessmgr_sw[i]->refcnt && strcasecmp (sessmgr_sw[i]->name, argv[1]) == 0)
  500.             break;
  501.     }
  502.     if (!sessmgr_sw[i]) {
  503.         tprintf ("Can't decipher session ID \"%s\"\n", argv[1]);
  504.         return 1;
  505.     }
  506.     /* reparent all of them! */
  507.     old = sessmgr_sw[i];
  508.     s = Current;
  509.     for (i = 0; (unsigned) i < Nsessions; i++) {
  510.         if (Sessions[i].screen->sessmgr != old)
  511.             continue;
  512.         sm_reparent (Sessions + i, argv[2]);
  513.         swapscreen (s, Sessions + i);
  514.         s = Sessions + i;
  515.     }
  516.     if (s == Current)
  517.         Sessions[i].screen->flags |= SMS_ACTIVE;
  518.     else
  519.         swapscreen (s, Current);
  520.     return 0;
  521. }
  522.  
  523.  
  524.  
  525. /*
  526.  * Ugly hack for doshell():  tell if the current session manager is SM_STDIO.
  527.  */
  528.  
  529. int
  530. sm_usestdio (void)
  531. {
  532.     return Current->screen->sessmgr->flags & SM_STDIO;
  533. }
  534.  
  535.  
  536.  
  537. /*
  538.  * Start a session with a specified session manager.  This could be static
  539.  * since it's normally only used by the "sessmgr <sm> create" command, but
  540.  * we also need it to start the trace session in a different session manager
  541.  * from the default.
  542.  *
  543.  * This incorporates newsession().  Ultimately, newsession() should be changed
  544.  * to call this function.
  545.  */
  546.  
  547. struct session *
  548. sm_newsession (const char *sc, const char *name, int type, int split)
  549. {
  550. struct session *sp;
  551. int i;
  552.  
  553.     if (!sc || !*sc) {
  554.         /*
  555.          * HACK - new sessions should inherit the current session if it is a
  556.          * COMMAND session.  Else use Command's next session, unless Command
  557.          * doesn't exist yet (creation of Command or Trace) in which case the
  558.          * default session manager is used.
  559.          *
  560.          * Maybe this isn't really a hack... but it feels like one.
  561.          */
  562.         if (Current && Current->screen && Current->type == COMMAND)
  563.             sc = Current->screen->next_sm;
  564.         else if (Command && Command->screen)
  565.             sc = Command->screen->next_sm;
  566.         else
  567.             sc = "";
  568.     }
  569.     if (type == TRACESESSION)
  570.         i = (int) (Nsessions - 1);
  571.     else {
  572.         for (i = 0; (unsigned) i < Nsessions; i++) {
  573.             if (Sessions[i].type == FREE)
  574.                 break;
  575.         }
  576.     }
  577.     if ((unsigned) i == Nsessions)
  578.         return NULLSESSION;
  579.     sp = Sessions + i;
  580.     sp->type = type;
  581.     sp->s = -1;
  582.     if (name != NULLCHAR)
  583.         sp->name = strdup (name);
  584.     sp->proc = Curproc;
  585.     /* update Curproc's session pointer as well! */
  586.     /* (in theory this could leave a dangling session...?) */
  587.     Curproc->session = sp;
  588.     /* Create standard input and output sockets. Output is
  589.      * translated to local end-of-line by default
  590.      */
  591.     Curproc->input = sp->input = socket (AF_LOCAL, SOCK_STREAM, 0);
  592.     (void) seteol (Curproc->input, Eol);
  593.     (void) sockmode (Curproc->input, SOCK_BINARY);
  594.     Curproc->output = sp->output = socket (AF_LOCAL, SOCK_STREAM, 0);
  595.     (void) seteol (Curproc->output, Eol);
  596.     (void) sockmode (Curproc->output, SOCK_ASCII);
  597.     /* on by default */
  598.     sp->ttystate.crnl = sp->ttystate.edit = sp->ttystate.echo = 1;
  599.     sp->flowmode = 0;    /* Off by default */
  600.     sp->row = Numrows;
  601.     sp->morewait = 0;
  602.     sp->split = split;
  603.     sp->tsavex = sp->tsavey = 1;
  604.     sm_newscreen (sc, sp);
  605.     swapscreen (Current, sp);
  606.     Current = sp;
  607.     return sp;
  608. }
  609.  
  610.  
  611.  
  612. /*
  613.  * Session manager initiation and cleanup.
  614.  */
  615.  
  616. void
  617. ioinit (int no_itimer)
  618. {
  619.     init_sys (no_itimer);
  620.     sesm_initted = 1;
  621. }
  622.  
  623.  
  624.  
  625. void
  626. iostop (void)
  627. {
  628. int c;
  629.  
  630.     sesm_initted = 0;
  631.     for (c = 0; sessmgr_sw[c]; c++) {
  632.         if (sessmgr_sw[c]->flags & SM_INIT)
  633.             (*sessmgr_sw[c]->end) (sessmgr_sw[c]);
  634.     }
  635.     deinit_sys ();
  636. }
  637.  
  638.  
  639.  
  640. /*
  641.  * Suspend and resume now only suspend/resume the current session manager.
  642.  * It is assumed that the session manger is SM_STDIO and that an outside
  643.  * process needs to intercept the SM_STDIO interface temporarily.
  644.  */
  645.  
  646. void
  647. iosuspend (void)
  648. {
  649. register struct screen *sp = Current->screen;
  650.  
  651.     if ((sp->sessmgr->flags & (SM_INIT | SM_SUSPEND)) == SM_INIT) {
  652.         (*sp->sessmgr->suspend) (sp->sessmgr);
  653.         sp->sessmgr->flags |= SM_SUSPEND;
  654.     }
  655. }
  656.  
  657.  
  658.  
  659. void
  660. ioresume (void)
  661. {
  662. register struct screen *sp = Current->screen;
  663.  
  664.     if ((sp->sessmgr->flags & (SM_INIT | SM_SUSPEND)) == (SM_INIT | SM_SUSPEND)) {
  665.         (*sp->sessmgr->resume) (sp->sessmgr);
  666.         sp->sessmgr->flags &= ~SM_SUSPEND;
  667.     }
  668. }
  669.  
  670.  
  671.  
  672. /*
  673.  * Session creation, destruction, and swapping.
  674.  */
  675.  
  676. void
  677. j_newscreen (struct session *sp)
  678. {
  679. char const *sc;
  680.  
  681.     if (Current && Current->screen && Current->type == COMMAND) {
  682.         sc = Current->screen->use_sm;
  683.         Current->screen->use_sm = Current->screen->next_sm;
  684.     } else if (Command && Command->screen)
  685.         sc = Command->screen->next_sm;
  686.     else
  687.         sc = "";
  688.     sm_newscreen (sc, sp);
  689. }
  690.  
  691.  
  692.  
  693. void
  694. freescreen (struct session *sp)
  695. {
  696.     if (!sp || !sp->screen)
  697.         return;
  698.     (*sp->screen->sessmgr->destroy) (sp->screen->sessmgr, sp->screen->sesmdat);
  699.     free (sp->screen->next_sm);
  700.     if (!--sp->screen->sessmgr->refcnt) {
  701.         (*sp->screen->sessmgr->end) (sp->screen->sessmgr);
  702.         sp->screen->sessmgr->flags &= ~SM_INIT;
  703.     }
  704.     free (sp->screen);
  705.     sp->screen = 0;
  706. }
  707.  
  708. extern struct session *ScreenOwner;    /* Session currently displayed */
  709.  
  710.  
  711.  
  712. void
  713. swapscreen (struct session *old, struct session *new)
  714. {
  715.     if (old == new)
  716.         return;
  717. #if 1
  718.     BLOCKStatline += 1;
  719. #endif
  720. #if 1
  721.     while (INStatline)
  722.         kwait (NULL);
  723. #endif
  724.     /*
  725.      * If they're in different session managers, swap each to/from NULL.
  726.      * Otherwise, swap them in the common session manager.
  727.      */
  728.     if (old && new && old->screen->sessmgr == new->screen->sessmgr) {
  729.         if (!(*old->screen->sessmgr->swtch) (old->screen->sessmgr,
  730.              old->screen->sesmdat, new->screen->sesmdat))
  731.             old->screen->flags &= ~SMS_ACTIVE;
  732.     } else {
  733.         if (old)
  734.             (void) (*old->screen->sessmgr->swtch) (old->screen->sessmgr, old->screen->sesmdat, 0);
  735.  
  736.         if (old && new && (old->screen->sessmgr->flags & SM_STDIO) &&
  737.             (new->screen->sessmgr->flags & SM_STDIO) &&
  738.             !(old->screen->sessmgr->flags & SM_SUSPEND)) {
  739.             (*old->screen->sessmgr->suspend) (old->screen->sessmgr);
  740.             old->screen->sessmgr->flags |= SM_SUSPEND;
  741.         }
  742.         if (new &&
  743.             ((new->screen->sessmgr->flags & (SM_SUSPEND | SM_STDIO | SM_INIT)) ==
  744.              (SM_SUSPEND | SM_STDIO | SM_INIT))) {
  745.             (*new->screen->sessmgr->resume) (new->screen->sessmgr);
  746.             new->screen->sessmgr->flags &= ~SM_SUSPEND;
  747.         }
  748.         if (new)
  749.             (void) (*new->screen->sessmgr->swtch) (new->screen->sessmgr, 0, new->screen->sesmdat);
  750.     }
  751.     ScreenOwner = new;
  752. #if 1
  753.     BLOCKStatline -= 1;
  754. #endif
  755.     if (new) {
  756.         new->screen->flags |= SMS_ACTIVE;
  757. #if 1
  758.         displayStatLine (0, 1, 0);
  759. #endif
  760.         ksignal (new->screen, 0);
  761.     }
  762. }
  763.  
  764.  
  765.  
  766. /*
  767.  * Some session managers (e.g. curses) aren't re-entrant.  We deal with this
  768.  * by locking individual screens.  (we assume the session manager is reentrant
  769.  * between separate screens; this may be unsafe...)
  770.  */
  771.  
  772. static int
  773. LOCKSCR (register struct screen *sc, int wait)
  774. {
  775. sigset_t s, t;
  776.  
  777.     (void) sigfillset (&s);
  778.     (void) sigprocmask (SIG_BLOCK, &s, &t);
  779.     while (sc->flags & SM_LOCK) {
  780.         if (!wait)
  781.             return 0;
  782.         kwait (&sc->flags);
  783.     }
  784.     sc->flags |= SM_LOCK;
  785.     (void) sigprocmask (SIG_SETMASK, &t, 0);
  786.     return 1;
  787. }
  788.  
  789.  
  790.  
  791. static void
  792. UNLOCKSCR (register struct screen *sc)
  793. {
  794. sigset_t s, t;
  795.  
  796.     (void) sigfillset (&s);
  797.     (void) sigprocmask (SIG_BLOCK, &s, &t);
  798.     sc->flags &= ~SM_LOCK;
  799.     ksignal (&sc->flags, 0);
  800.     (void) sigprocmask (SIG_SETMASK, &t, 0);
  801. }
  802.  
  803.  
  804.  
  805. /*
  806.  * I/O routines come in two flavors.  The internal ones, which start with
  807.  * "s", are used by rflush() and by the external ones.  The external ones are
  808.  * used by the rest of NOS.
  809.  */
  810.  
  811. static void
  812. sputch (struct session *s, int c)
  813. {
  814.     (*s->screen->sessmgr->putch) (s->screen->sessmgr, s->screen->sesmdat, c);
  815. }
  816.  
  817.  
  818.  
  819. static void
  820. scputs (struct session *s, const char *str)
  821. {
  822. register struct screen *sp;
  823.  
  824.     sp = s->screen;
  825.     while (*str)
  826.         (*sp->sessmgr->putch) (sp->sessmgr, sp->sesmdat, *str++);
  827. }
  828.  
  829.  
  830.  
  831. static void
  832. sclreol (struct session *s)
  833. {
  834.     (*s->screen->sessmgr->clreol) (s->screen->sessmgr, s->screen->sesmdat);
  835. }
  836.  
  837.  
  838.  
  839. /*
  840.  * rflush() used to flush data to the display process.  Now it does I/O itself;
  841.  * the display process is defunct.
  842.  */
  843.  
  844. void
  845. rflush (void)
  846. {
  847. struct session *sp;
  848. int i, c, statsize;
  849.  
  850.     if (!Sessions || !sesm_initted)
  851.         return;        /* timer could tick before we exist, or while suspended */
  852. #ifdef SCREENSAVER
  853.     if (!ssenabled ())
  854. #endif
  855.     {
  856.         for (sp = Sessions, i = 0; (unsigned) i < Nsessions; sp++, i++) {
  857.             if (sp->type == FREE)
  858.                 continue;
  859.             if (!sp->screen || !sp->screen->sessmgr || !sp->screen->sesmdat)
  860.                 continue;
  861.             if (!(sp->screen->flags & SMS_ACTIVE) || sp->morewait == 1)
  862.                 continue;
  863.             /* err, do I want to do this? */
  864.             if (sp->screen->sessmgr->flags & SM_SUSPEND)
  865.                 continue;
  866. #ifdef SCREENSAVER
  867.             if (ssenabled ())
  868.                 continue;
  869. #endif
  870.  
  871.             if (!LOCKSCR (sp->screen, 0)) {
  872.                 write (2, "screen not responding - still trying\r\n", 38);
  873.                 continue;
  874.             }
  875.             (*sp->screen->sessmgr->rflush) (sp->screen->sessmgr,
  876.                             sp->screen->sesmdat);
  877.             if (sp->morewait == 2) {
  878.                 sp->morewait = 0;
  879.                 sputch (sp, '\r');
  880.                 sclreol (sp);
  881.             }
  882.             while (socklen (sp->output, 0) > 0) {
  883.                 if ((c = rrecvchar (sp->output)) == EOF)
  884.                     continue;
  885.                 if (!sp->split || c != 0x0a)
  886.                     sputch (sp, c);
  887.                 else {
  888.                     scputs (sp, Eol);
  889.                     sclreol (sp);
  890.                 }
  891.                 if (sp->record != NULLFILE) {
  892.                     if (c == '\r' || c == '\n')
  893.                         (void) fflush (sp->record);
  894.                     if (c != '\r' || sockmode (sp->output, -1) != SOCK_ASCII)
  895.                         (void) putc (c, sp->record);
  896.                 }
  897.                 statsize = 0;
  898.                 if (sp->screen->statline)
  899.                     statsize = ((sp == Command) ? getStatlines() : 1);
  900.  
  901.                 if (sp->flowmode && c == '\n' && sp->row > 0 && --sp->row == statsize) {
  902.                     scputs (sp, "--More--");
  903.                     sp->morewait = 1;
  904.                     sp->row = 0;
  905.                     break;
  906.                 }
  907.             }
  908.             (*sp->screen->sessmgr->flush) (sp->screen->sessmgr, sp->screen->sesmdat);
  909.             UNLOCKSCR (sp->screen);
  910.         }
  911.     }
  912. }
  913.  
  914.  
  915.  
  916. /*
  917.  * Public output routines.  getcursess() attempts to intuit the correct session
  918.  * for output.
  919.  */
  920.  
  921. static struct session *
  922. getcursess (void)
  923. {
  924. static struct proc *kbproc = NULLPROC;
  925.  
  926.     /* this is a horrible hack that will (MUST!) go away in the future */
  927.     if (!kbproc && Curproc && strcmp (Curproc->name, "keyboard") == 0)
  928.         kbproc = Curproc;
  929.     if (kbproc == Curproc)
  930.         return Current;
  931.     /*
  932.      * if Curproc's session isn't active we must block...
  933.      * N.B. should handle trace with a special flag indicating that the
  934.      * session should discard output instead of blocking
  935.      */
  936.     if (!(Curproc->session->screen->flags & SMS_ACTIVE)) {
  937. #if 0
  938.         if (Curproc->session->screen->flags & SMS_DISCARD)
  939.             return 0;
  940. #endif
  941.         kwait (Current->screen);
  942.     }
  943. #if 1
  944.     return Current;
  945. #else
  946.     return Curproc->session;
  947. #endif
  948. }
  949.  
  950.  
  951.  
  952. void
  953. putch (int c)
  954. {
  955. struct session *sp;
  956.  
  957.     sp = getcursess ();
  958.     (void) LOCKSCR (sp->screen, 1);
  959.     sputch (sp, c);
  960.     UNLOCKSCR (sp->screen);
  961. }
  962.  
  963.  
  964.  
  965. void
  966. cputs (const char *s)
  967. {
  968. struct session *sp;
  969.  
  970.     sp = getcursess ();
  971.     (void) LOCKSCR (sp->screen, 1);
  972.     scputs (sp, s);
  973.     UNLOCKSCR (sp->screen);
  974. }
  975.  
  976.  
  977.  
  978. void
  979. clreol (void)
  980. {
  981. struct session *sp;
  982.  
  983.     sp = getcursess ();
  984.     (void) LOCKSCR (sp->screen, 1);
  985.     sclreol (sp);
  986.     UNLOCKSCR (sp->screen);
  987. }
  988.  
  989.  
  990.  
  991. void
  992. clrscr (void)
  993. {
  994. register struct screen *sp;
  995.  
  996.     sp = getcursess ()->screen;
  997.     (void) LOCKSCR (sp, 1);
  998.     (*sp->sessmgr->clrscr) (sp->sessmgr, sp->sesmdat);
  999.     UNLOCKSCR (sp);
  1000. }
  1001.  
  1002.  
  1003.  
  1004. int
  1005. wherex (void)
  1006. {
  1007. register struct screen *sp;
  1008. int i;
  1009.  
  1010.     sp = getcursess ()->screen;
  1011.     if (sp->sessmgr->wherex) {
  1012.         (void) LOCKSCR (sp, 1);
  1013.         i = (*sp->sessmgr->wherex) (sp->sessmgr, sp->sesmdat);
  1014.         UNLOCKSCR (sp);
  1015.         return i;
  1016.     }
  1017.     return -1;
  1018. }
  1019.  
  1020.  
  1021.  
  1022. int
  1023. wherey (void)
  1024. {
  1025. register struct screen *sp;
  1026. int i;
  1027.  
  1028.     sp = getcursess ()->screen;
  1029.     if (sp->sessmgr->wherey) {
  1030.         (void) LOCKSCR (sp, 1);
  1031.         i = (*sp->sessmgr->wherey) (sp->sessmgr, sp->sesmdat);
  1032.         UNLOCKSCR (sp);
  1033.         return i;
  1034.     }
  1035.     return -1;
  1036. }
  1037.  
  1038.  
  1039.  
  1040. void
  1041. window (int x1, int y1, int x2, int y2)
  1042. {
  1043. register struct screen *sp;
  1044.  
  1045.     sp = getcursess ()->screen;
  1046.     if (sp->sessmgr->window) {
  1047.         (void) LOCKSCR (sp, 1);
  1048.         (*sp->sessmgr->window) (sp->sessmgr, sp->sesmdat, x1, y1, x2, y2);
  1049.         UNLOCKSCR (sp);
  1050.     }
  1051. }
  1052.  
  1053.  
  1054.  
  1055. void
  1056. gotoxy (int x, int y)
  1057. {
  1058. register struct screen *sp;
  1059.  
  1060.     sp = getcursess ()->screen;
  1061.     (void) LOCKSCR (sp, 1);
  1062.     (*sp->sessmgr->gotoxy) (sp->sessmgr, sp->sesmdat, x, y);
  1063.     UNLOCKSCR (sp);
  1064. }
  1065.  
  1066.  
  1067.  
  1068. void
  1069. highvideo (void)
  1070. {
  1071. register struct screen *sp;
  1072.  
  1073.     sp = getcursess ()->screen;
  1074.     (void) LOCKSCR (sp, 1);
  1075.     (*sp->sessmgr->high) (sp->sessmgr, sp->sesmdat);
  1076.     UNLOCKSCR (sp);
  1077. }
  1078.  
  1079.  
  1080.  
  1081. void
  1082. normvideo (void)
  1083. {
  1084. register struct screen *sp;
  1085.  
  1086.     sp = getcursess ()->screen;
  1087.     (void) LOCKSCR (sp, 1);
  1088.     (*sp->sessmgr->norm) (sp->sessmgr, sp->sesmdat);
  1089.     UNLOCKSCR (sp);
  1090. }
  1091.  
  1092.  
  1093. void
  1094. textbackground (int color)
  1095. {
  1096. register struct screen *sp;
  1097.  
  1098.     sp = getcursess ()->screen;
  1099.     (void) LOCKSCR (sp, 1);
  1100.     (*sp->sessmgr->bground) (sp->sessmgr, sp->sesmdat, color);
  1101.     UNLOCKSCR (sp);
  1102. }
  1103.  
  1104.  
  1105. void
  1106. textcolor (int color)
  1107. {
  1108. register struct screen *sp;
  1109.  
  1110.     sp = getcursess ()->screen;
  1111.     (void) LOCKSCR (sp, 1);
  1112.     (*sp->sessmgr->fground) (sp->sessmgr, sp->sesmdat, color);
  1113.     UNLOCKSCR (sp);
  1114. }
  1115.  
  1116.  
  1117. void
  1118. textattr (int color)
  1119. {
  1120. register struct screen *sp;
  1121.  
  1122.     sp = getcursess ()->screen;
  1123.     (void) LOCKSCR (sp, 1);
  1124.     (*sp->sessmgr->txtattr) (sp->sessmgr, sp->sesmdat, color);
  1125.     UNLOCKSCR (sp);
  1126. }
  1127.  
  1128.  
  1129. void
  1130. textrefresh (void)
  1131. {
  1132. register struct screen *sp;
  1133.  
  1134.     sp = getcursess ()->screen;
  1135.     (void) LOCKSCR (sp, 1);
  1136.     (*sp->sessmgr->refresh) (sp->sessmgr, sp->sesmdat);
  1137.     UNLOCKSCR (sp);
  1138. }
  1139.  
  1140.  
  1141. void
  1142. _setcursortype (int t)
  1143. {
  1144. register struct screen *sp;
  1145.  
  1146.     sp = getcursess ()->screen;
  1147.     if (sp->sessmgr->cursor) {
  1148.         (void) LOCKSCR (sp, 1);
  1149.         (*sp->sessmgr->cursor) (sp->sessmgr, sp->sesmdat, t);
  1150.         UNLOCKSCR (sp);
  1151.     }
  1152. }
  1153.  
  1154.  
  1155.  
  1156. int
  1157. kbread (void)
  1158. {
  1159. register struct screen *sp;
  1160.  
  1161.     sp = getcursess ()->screen;
  1162.     return (*sp->sessmgr->kbread) (sp->sessmgr, sp->sesmdat);
  1163. }
  1164.  
  1165.  
  1166.  
  1167. /*
  1168.  * The status entry point is different:  any routine may call the status output
  1169.  * routine, which calls the status switch entry for the Command screen.  If
  1170.  * that is NULL, we perform direct output without passing information to
  1171.  * rflush(); this avoids the flow control problems which have plagued previous
  1172.  * versions, although it requires that we duplicate parts of rflush() here
  1173.  * (and it's ugly).
  1174.  *
  1175.  * The numeric argument is presently ignored.  Eventually I may use it for
  1176.  * a positioning hint.
  1177.  */
  1178.  
  1179. void
  1180. sm_status (int pos, char *str)
  1181. {
  1182. struct screen *cs;
  1183.  
  1184.     cs = Command->screen;
  1185.     if (cs->sessmgr->status)
  1186.         (*cs->sessmgr->status) (cs->sessmgr, cs->sesmdat, pos, str);
  1187.     else {
  1188.         if (cs->sessmgr->flags & SM_SUSPEND)
  1189.             return;
  1190.         if (!(cs->flags & SMS_ACTIVE))
  1191.             return;
  1192.         (void) LOCKSCR (cs, 1);
  1193.         (*cs->sessmgr->rflush) (cs->sessmgr, cs->sesmdat);
  1194.         /* should translate \n to Eol */
  1195.         scputs (Command, str);
  1196. #if 0
  1197.         scputs (Command, Eol);
  1198. #endif
  1199.         (*cs->sessmgr->flush) (cs->sessmgr, cs->sesmdat);
  1200.         UNLOCKSCR (cs);
  1201.     }
  1202. }
  1203.  
  1204. #endif         /* UNIX */
  1205.